/*
 Copyright (C) 2009 QDSS.org
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.qdss.persist.exception;

import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

import org.qdss.persist.exception.jdbc.ConstraintViolationException;
import org.qdss.persist.exception.jdbc.GenericJDBCException;
import org.qdss.persist.exception.jdbc.LockAcquisitionException;
import org.qdss.persist.exception.jdbc.SQLSyntaxException;


/**
 * 
 * 
 * @author <a href="mailto:devezhao@126.com">FANGFANG ZHAO</a>
 * @since 0.1.0, 03/19/08
 * @version $Id: SQLExceptionConverter.java 44 2009-04-17 07:25:34Z zhaofang123@gmail.com $
 */
public class SQLExceptionConverter {

	private static final Set<String> SQL_GRAMMAR_CATEGORIES = new HashSet<String>();
	private static final Set<String> DATA_CATEGORIES = new HashSet<String>();
	private static final Set<String> INTEGRITY_VIOLATION_CATEGORIES = new HashSet<String>();
	private static final Set<String> CONNECTION_CATEGORIES = new HashSet<String>();
	
	// error code
	static {
		SQL_GRAMMAR_CATEGORIES.add("07");
		SQL_GRAMMAR_CATEGORIES.add("37");
		SQL_GRAMMAR_CATEGORIES.add("42");
		SQL_GRAMMAR_CATEGORIES.add("65");
		SQL_GRAMMAR_CATEGORIES.add("S0");
		SQL_GRAMMAR_CATEGORIES.add("20");

		DATA_CATEGORIES.add("22");
		DATA_CATEGORIES.add("21");
		DATA_CATEGORIES.add("02");

		INTEGRITY_VIOLATION_CATEGORIES.add("23");
		INTEGRITY_VIOLATION_CATEGORIES.add("27");
		INTEGRITY_VIOLATION_CATEGORIES.add("44");

		CONNECTION_CATEGORIES.add("08");
	}
	
	/**
	 */
	private SQLExceptionConverter() { }

	/**
	 * Converter jdbc exception
	 * 
	 * @param sqlex
	 * @param message
	 * @param sql
	 * @return
	 */
	public static JDBCException convert(SQLException sqlex, String message, String sql) {
		String stateCode = sqlex.getSQLState();

		if (stateCode != null && stateCode.length() >= 2) {
			String classCode = stateCode.substring(0, 2);
			
			if (SQL_GRAMMAR_CATEGORIES.contains(classCode)) {
				return new SQLSyntaxException(message, sqlex, sql);
			} else if (INTEGRITY_VIOLATION_CATEGORIES.contains(classCode)) {
				return new ConstraintViolationException(message, sqlex, sql);
			}
		}

		if ("40001".equals(stateCode)) {
			return new LockAcquisitionException(message, sqlex, sql);
		}

		if ("61000".equals(stateCode)) {
			// oracle sql-state code for deadlock
			return new LockAcquisitionException(message, sqlex, sql);
		}
		
		return handledNonSpecificException(sqlex, message, sql);
	}

	/**
	 * non-specific sql exception
	 * 
	 * @param sqlex
	 * @param message
	 * @param sql
	 * @return
	 */
	private static JDBCException handledNonSpecificException(SQLException sqlex,
			String message, String sql) {
		return new GenericJDBCException(message, sqlex, sql);
	}
}
